package com.aabte.permissionframeworklearn.permission.service;

import com.aabte.permissionframeworklearn.permission.common.RequestHolder;
import com.aabte.permissionframeworklearn.permission.exception.ParamException;
import com.aabte.permissionframeworklearn.permission.mapper.SysDeptMapper;
import com.aabte.permissionframeworklearn.permission.mapper.SysUserMapper;
import com.aabte.permissionframeworklearn.permission.model.SysDept;
import com.aabte.permissionframeworklearn.permission.param.DeptParam;
import com.aabte.permissionframeworklearn.permission.util.BeanValidator;
import com.aabte.permissionframeworklearn.permission.util.IpUtil;
import com.aabte.permissionframeworklearn.permission.util.LevelUtil;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * @author Daniel
 */
@Slf4j
@Service
public class SysDeptService {

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysLogService sysLogService;

    public SysDept save(DeptParam deptParam) {
        log.info("Start save. deptParam: {}", deptParam);

        BeanValidator.check(deptParam);

        if (checkExist(deptParam.getParentId(), deptParam.getName(), deptParam.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门");
        }

        SysDept.SysDeptBuilder sysDeptBuilder = SysDept.builder()
                .name(deptParam.getName())
                .parentId(deptParam.getParentId())
                .seq(deptParam.getSeq())
                .remark(deptParam.getRemark());

        String level = LevelUtil.calculateLevel(getLevel(deptParam.getParentId()), deptParam.getParentId());
        sysDeptBuilder.level(level);

        sysDeptBuilder.operator(RequestHolder.getCurrentUser().getUsername());
        sysDeptBuilder.operateIp(IpUtil.getRemoteIpAddress(RequestHolder.getCurrentRequest()));
        sysDeptBuilder.operateTime(new Date());

        SysDept sysDept = sysDeptBuilder.build();

        sysDeptMapper.insertSelective(sysDept);
        sysLogService.saveDeptLog(null, sysDept);

        log.info("End save. sysDept: {}", sysDept);
        return sysDept;
    }

    private String getLevel(Long deptId) {
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (null == sysDept) {
            return null;
        }
        return sysDept.getLevel();
    }

    private boolean checkExist(Long parentId, String deptName, Long deptId) {
        long count = sysDeptMapper.countByNameAndParentId(parentId, deptName, deptId);
        return count > 0;
    }

    public SysDept update(DeptParam deptParam) {
        log.info("Start update. deptParam: {}", deptParam);

        BeanValidator.check(deptParam);

        if (checkExist(deptParam.getParentId(), deptParam.getName(), deptParam.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门");
        }

        SysDept before = sysDeptMapper.selectByPrimaryKey(deptParam.getId());
        Preconditions.checkNotNull(before, "待更新的部门不存在！");

        SysDept.SysDeptBuilder sysDeptBuilder = SysDept.builder()
                .id(deptParam.getId())
                .name(deptParam.getName())
                .parentId(deptParam.getParentId())
                .seq(deptParam.getSeq())
                .remark(deptParam.getRemark());

        String level = LevelUtil.calculateLevel(getLevel(deptParam.getParentId()), deptParam.getParentId());
        sysDeptBuilder.level(level);

        sysDeptBuilder.operator(RequestHolder.getCurrentUser().getUsername());
        sysDeptBuilder.operateIp(IpUtil.getRemoteIpAddress(RequestHolder.getCurrentRequest()));
        sysDeptBuilder.operateTime(new Date());

        SysDept after = sysDeptBuilder.build();

        updateWithChild(before, after);
        sysLogService.saveDeptLog(before, after);

        log.info("End update. sysDept: {}", after);
        return after;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateWithChild(SysDept before, SysDept after) {
        log.info("Start updateWithChild. before: {}, after: {}", before, after);

        sysDeptMapper.updateByPrimaryKey(after);

        String newLevelPrefix = after.getLevel();
        String oldLevelPrefix = before.getLevel();
        if (!StringUtils.equals(after.getLevel(), before.getLevel())) {
            List<SysDept> depts = sysDeptMapper.getChildDeptListByLevel(oldLevelPrefix);
            if (CollectionUtils.isNotEmpty(depts)) {
                for (SysDept dept : depts) {
                    String level = dept.getLevel();
                    if (level.indexOf(oldLevelPrefix) == 0) {
                        level = newLevelPrefix + level.substring(oldLevelPrefix.length());
                        dept.setLevel(level);
                    }
                }
                sysDeptMapper.batchUpdateLevel(depts);
            }
        }
        sysDeptMapper.updateByPrimaryKey(after);

        log.info("End updateWithChild. after: {}", after);
    }

    @Transactional(rollbackFor = Exception.class)
    public SysDept delete(Long deptId) {
        log.info("Start delete. deptId: {}", deptId);
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        Preconditions.checkNotNull(sysDept, "待删除部门不存在！");

        boolean isExistChild = sysDeptMapper.countByParentId(sysDept.getId()) > 0;
        if (isExistChild) {
            throw new ParamException("当前部门下面子部门，无法删除！");
        }

        boolean isExistUsers = sysUserMapper.countByDeptId(sysDept.getId()) > 0;
        if (isExistUsers) {
            throw new ParamException("当前部门下有用户，无法删除！");
        }

        sysDeptMapper.deleteByPrimaryKey(deptId);
        return sysDept;
    }
}
